﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Diagnostics;
using System.Windows.Threading;
using System.Runtime.Serialization;
using Curling.CurlingServer;

namespace Curling
{
    [DataContractAttribute]
    public class AIManager
    {
        public GameManager gameManager { get; set; }

        static Random rand;

        [DataMemberAttribute]
        public bool PerformDelivery = false;
        [DataMemberAttribute]
        public double PushDirection;
        [DataMemberAttribute]
        public double PushVelocity;

        //DispatcherTimer Timer;
        [DataMemberAttribute]
        public DateTime MakeActiveTimeStamp;

        static AIManager()
        {
            rand = new Random();
        }

        public AIManager(GameManager gameManager)
        {
            this.gameManager = gameManager;            
        }

        public void NewRound()
        {
            PerformDelivery = false;
        }

        public void Update()
        {
            if (!PerformDelivery && gameManager.gameState == GameState.StoneOnStart)
            {
                int CurrentResult = ((gameManager.ActivePlayer == PlayerColor.Yellow) ? 1 : -1) * gameManager.GetRoundResult();

                if (CurrentResult > 0 && rand.Next(0, 3) == 0)
                {
                    // Ставить защитника

                    FindPushParameters(out PushVelocity, out PushDirection, PushType.Defence);
                    Debug.WriteLine("защита. " + PushVelocity + " " + PushDirection);
                }
                else
                {
                    // Бросать в дом или выбивать противника                    

                    double OpponentDistanceToButton = double.MaxValue;

                    foreach (Stone stone in gameManager.Stones)
                    {
                        OpponentDistanceToButton = Math.Min(OpponentDistanceToButton, stone.stoneEntity.DistanceToButton);
                    }

                    double ClearPathOffset = FindClearPathOffset();
                    //ClearPathOffset = 0.0;
                    if (!double.IsNaN(ClearPathOffset))
                    {
                        if (OpponentDistanceToButton < Math.Abs(ClearPathOffset) && CurrentResult < 0)
                        {
                            // выбивать
                            FindPushParameters(out PushVelocity, out PushDirection, PushType.Attack);
                            Debug.WriteLine("выбивать. " + PushVelocity + " " + PushDirection);
                        }
                        else
                        {
                            // в дом
                            FindPushParameters(out PushVelocity, out PushDirection, PushType.ToHouse);
                            PushDirection += ClearPathOffset / 100;

                            if (CurrentResult < 0)
                            {
                                foreach (Stone stone in gameManager.Stones)
                                {
                                    if (stone.stoneEntity.State == StoneState.OnRink)
                                    {
                                        if (stone.stoneEntity.DistanceToButton < StoneEntity.Radius * 2)
                                        {
                                            PushVelocity += 0.15;
                                            Debug.WriteLine("в дом + проталкивать");
                                            break;
                                        }
                                    }
                                }
                            }
                            Debug.WriteLine("в дом. " + PushVelocity + " " + PushDirection);
                        }
                    }
                    else
                    {
                        if (CurrentResult > 0)
                        {
                            // Ставить защитника

                            FindPushParameters(out PushVelocity, out PushDirection, PushType.Defence);
                            Debug.WriteLine("защита. " + PushVelocity + " " + PushDirection);
                        }
                        else
                        {
                            // выбивать
                            FindPushParameters(out PushVelocity, out PushDirection, PushType.Attack);
                            Debug.WriteLine("выбивать. " + PushVelocity + " " + PushDirection);
                        }
                    }
                }

                //PushDirection = ((rand.NextDouble() + rand.NextDouble()) - 1) * 2;
                MakeActiveTimeStamp = DateTime.Now;
                PerformDelivery = true;
                //Debug.WriteLine(PushVelocity);
            }

            if (PerformDelivery)
            {
                //Debug.WriteLine(gameManager.CurrentGameTime.TotalSeconds.ToString());

                if (gameManager.gameState == GameState.StoneOnStart)
                {
                    TimeSpan FromMakeActive = DateTime.Now.Subtract(MakeActiveTimeStamp);

                    if (FromMakeActive < TimeSpan.FromSeconds(3))
                    {
                        gameManager.RotateDeliveryStone(PushDirection * FromMakeActive.TotalSeconds / 3.0);
                    }
                    else
                    {
                        gameManager.PushStone();
                    }
                }

                if (gameManager.gameState == GameState.StonePushed && gameManager.CurrentGameTime > TimeSpan.FromSeconds(1.9 - PushVelocity))
                {                    
                    gameManager.LeaveStone();
                }                
            }
        }

        private double FindClearPathOffset()
        {
            int[] offset = new int[] { 0, -25, 50, -75, 100, -125, 150, -200, 250 };

            for (int i = 0; i < offset.Length; i++)
            {
                bool Continue = false;

                foreach (Stone stone in gameManager.Stones)
                {
                    if (stone.stoneEntity.State == StoneState.OnRink)
                    {
                        if (stone.stoneEntity.Y < GameManager.RinkLength - GameManager.Teeline)
                        {
                            if (stone.stoneEntity.X + StoneEntity.Radius * 3 > GameManager.Centerline + offset[i] && stone.stoneEntity.X - StoneEntity.Radius * 3 < GameManager.Centerline + offset[i])
                            {
                                Continue = true;
                                break;
                            }
                        }
                    }
                }

                if (!Continue)
                    return offset[i];
            }

            return double.NaN;
        }

        private void FindPushParameters(out double Velocity, out double Direction, PushType pushType)
        {
            Velocity = 0.0;
            Direction = 0.0;

            switch (pushType)
            {
                case PushType.Defence:
                {
                    Velocity = (rand.NextDouble() + rand.NextDouble()) * 0.05;
                    Direction = ((rand.NextDouble() + rand.NextDouble()) - 1) * 0.6;

                    break;
                }
                case PushType.Attack:
                {
                    Velocity = rand.NextDouble() * 0.3 + 0.7;
                    Direction = ((rand.NextDouble() + rand.NextDouble()) - 1) * 0.7;

                    break;
                }
                case PushType.ToHouse:
                {
                    Velocity = rand.NextDouble() * 0.2 + 0.4;
                    Direction = ((rand.NextDouble() + rand.NextDouble()) - 1) * 0.3;

                    break;
                }
            }
        }

        enum PushType
        { 
            Defence,
            Attack,
            ToHouse
        }
    }
}
